/**
  ******************************************************************************
  * @file    tc32l010_rcc.c
  * @author  CHIPAT Application Team
  * @brief   RCC HAL module driver.
  *          This file provides firmware functions to manage the following
  *          functionalities of the Reset and Clock Control (RCC) peripheral:
  *           + Initialization and de-initialization functions
  *           + Peripheral Control functions
  *
  @verbatim
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "tc32l010_rcc.h"

/* RCC Flag Mask */
#define FLAG_MASK ((uint8_t)0x1F)

/* CR register byte 1 (Bits[15:8]) base address */
#define CR_BYTE1_ADDRESS (RCC_BASE + 0x01)

/* Private variables ---------------------------------------------------------*/
// static __I uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};

/**
 * @brief  Resets the RCC clock configuration to the default reset state.
 * @note   The default reset state of the clock configuration is given below:
 * @note      HSI ON and used as system clock source
 * @note      AHB, APB prescaler set to 1.
 * @note      CSS and MCO OFF
 * @note      All interrupts disabled
 * @note   However, this function doesn't modify the configuration of the
 * @note      Peripheral clocks
 * @note      LSI, LSE and RTC clocks
 * @param  None
 * @retval None
 */
void RCC_DeInit(void)
{
    /* Set HSION bit */
    RCC->CSR |= (uint32_t)0x00000001;

    /* Reset SW[1:0],PPRE[1:0] ,HPRE[2:0] and MCOSEL[2:0],MCOEN[0],MCOPRE[1:0] bits */
    RCC->CFGR &= (uint32_t)0xFFCFF80;

    /* Reset HSEON, CSSON and  bits */
    RCC->CSR &= (uint32_t)0xFFFEFEFF;

    /* Reset LPUARTSW[1:0], LPTIM1SW,LPTIM1SW,I2C0SW,I2C1SW, RNGSW and ADCSW bits */
    // RCC->PERIENR = (uint32_t)0x00000000;
}

/**
 * @brief  Configures the External High Speed oscillator (HSE).
 * @note   After enabling the HSE (RCC_HSE_ON or RCC_HSE_Bypass), the application
 *         software should wait on HSERDY flag to be set indicating that HSE clock
 *         is stable and can be used to clock the PLL and/or system clock.
 * @note   The HSE is stopped by hardware when entering STOP and STANDBY modes.
 * @note   This function resets the CSSON bit, so if the Clock security system(CSS)
 *         was previously enabled you have to enable it again after calling this
 *         function.
 * @param  RCC_HSE: specifies the new state of the HSE.
 *          This parameter can be one of the following values:
 *            @arg RCC_HSE_OFF: turn OFF the HSE oscillator, HSERDY flag goes low after
 *                              6 HSE oscillator clock cycles.
 *            @arg RCC_HSE_ON: turn ON the HSE oscillator
 * @retval None
 */
void RCC_HSEConfig(uint8_t RCC_HSE)
{
    uint8_t reg;

    /* Check the parameters */
    assert_param(IS_RCC_HSE(RCC_HSE));

    reg = *(__IO uint8_t *)CR_BYTE1_ADDRESS;

    /* Reset HSEON and HSEBYP bits before configuring the HSE ------------------*/
    *(__IO uint8_t *)CR_BYTE1_ADDRESS = reg & (uint8_t)(~RCC_HSE_OFF);

    /* Set the new HSE configuration -------------------------------------------*/
    *(__IO uint8_t *)CR_BYTE1_ADDRESS = reg | RCC_HSE;
}

/**
 * @brief  Waits for HSE start-up.
 * @note   This function waits on HSERDY flag to be set and return SUCCESS if
 *         this flag is set, otherwise returns ERROR if the timeout is reached
 *         and this flag is not set. The timeout value is defined by the constant
 *         HSE_STARTUP_TIMEOUT in stm32l010.h file. You can tailor it depending
 *         on the HSE crystal used in your application.
 * @note   The HSE is stopped by hardware when entering STOP and STANDBY modes.
 * @param  None
 * @retval An ErrorStatus enumeration value:
 *          - SUCCESS: HSE oscillator is stable and ready to use
 *          - ERROR: HSE oscillator not yet ready
 */
ErrorStatus RCC_WaitForHSEStartUp(void)
{
    __IO uint32_t StartUpCounter = 0;
    ErrorStatus status = ERROR;
    FlagStatus HSEStatus = RESET;

    /* Wait till HSE is ready and if timeout is reached exit */
    do
    {
        HSEStatus = RCC_GetFlagStatus(RCC_FLAG_HSERDY);
        StartUpCounter++;
    } while ((StartUpCounter != HSE_STARTUP_TIMEOUT) && (HSEStatus == RESET));

    if ((RCC->CSR & RCC_CSR_HSERDY) != RESET)
    {
        status = SUCCESS;
    }
    else
    {
        status = ERROR;
    }
    return (status);
}

/**
 * @brief  Set the Internal High Speed oscillator (HSI) range.
 * @param  HSIRange: specifies the HSI range.
 *          This parameter can be one of the following values:
 *             @arg RCC_HSIRANGE_4MHZ: 4MHz.
 *             @arg RCC_HSIRANGE_16MHZ: 16MHz.
 *             @arg RCC_HSIRANGE_24MHZ: 24MHz.
 * @retval None
 */
void RCC_SetHSIRange(uint8_t HSIRange)
{
    uint32_t tmpreg = 0;

    tmpreg = RCC->CSR;

    tmpreg &= ~RCC_CSR_HSIRANGE;

    RCC->CSR = tmpreg | (HSIRange << 2);
}

/**
 * @brief  Adjusts the Internal High Speed oscillator (HSI) calibration value.
 * @note   The calibration is used to compensate for the variations in voltage
 *         and temperature that influence the frequency of the internal HSI RC.
 *         Refer to the Application Note AN4067 for more details on how to
 *         calibrate the HSI.
 * @param  HSICalibrationValue: specifies the HSI calibration value.
 *          This parameter must be a number between 0 and 0x3F.
 * @param  HSITrimmingValue: specifies the HSI trimming value.
 *          This parameter must be a number between 0 and 0x3F.
 * @retval None
 */
void RCC_AdjustHSICalibrationValue(uint8_t HSICalibrationValue, uint8_t HSITrimmingValue)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_HSI_CALIBRATION_VALUE(HSICalibrationValue));
    assert_param(IS_RCC_HSI_CALIBRATION_VALUE(HSITrimmingValue));

    tmpreg = RCC->ICSCR;

    /* Clear HSITRIM[5:0] bits */
    tmpreg &= ~(RCC_ICSCR_HSITRIM | RCC_ICSCR_HSICAL);

    /* Set the HSITRIM[5:0] bits according to HSICalibrationValue value */
    tmpreg |= ((uint32_t)HSITrimmingValue << 6);

    /* Store the new value */
    RCC->ICSCR = tmpreg | HSICalibrationValue;
}

/**
 * @brief  Adjusts the Internal LOW Speed oscillator (LSI) calibration value.
 * @note   The calibration is used to compensate for the variations in voltage
 *         and temperature that influence the frequency of the internal LSI RC.
 *         Refer to the Application Note AN4067 for more details on how to
 *         calibrate the LSI.
 * @param  LSICalibrationValue: specifies the LSI calibration value.
 *          This parameter must be a number between 0 and 0x3F.
 * @param  LSITrimmingValue: specifies the LSI trimming value.
 *          This parameter must be a number between 0 and 0xF.
 * @retval None
 */
void RCC_AdjustLSICalibrationValue(uint8_t LSICalibrationValue, uint8_t LSITrimmingValue)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_LSI_CALIBRATION_VALUE(LSICalibrationValue));
    assert_param(IS_RCC_LSI_TRIMMING_VALUE(LSITrimmingValue));

    tmpreg = RCC->LCSCR;

    /* Clear LSITRIM[3:0] bits */
    tmpreg &= ~(RCC_LCSCR_LSITRIM | RCC_LCSCR_LSICAL);

    /* Set the LSITRIM[3:0] bits according to LSICalibrationValue value */
    tmpreg |= (((uint32_t)LSITrimmingValue) | ((uint32_t)LSICalibrationValue << 4));

    /* Store the new value */
    RCC->LCSCR = tmpreg;
}

/**
 * @brief  Configures the clock stabilization time.
 * @param  RCC_CLKSource: defines the clock source.
 *          This parameter can be one of the following values:
 *             @arg RCC_StabilizationSource_HSE: HSE clock.
 *             @arg RCC_StabilizationSource_HSI: HSI clock.
 *             @arg RCC_StabilizationSource_LSI: LSI clock.
 *             @arg RCC_StabilizationSource_LSE: LSE clock.
 * @param  RCC_Time:specifies the stabilization time value.
 *          This parameter must be a number between 0 and 0x3.
 * @retval None
 */
void RCC_SetClockStabilizationTime(uint8_t RCC_CLKSource, uint8_t RCC_Time)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_STABILIZATION_SOURCE(RCC_CLKSource));
    assert_param(IS_RCC_STABILIZATION_TIME(RCC_Time));

    switch (RCC_CLKSource)
    {
    case RCC_StabilizationSource_HSE:
        tmpreg = RCC->CSR;
        tmpreg &= ~RCC_CSR_STARTUPHSE;
        RCC->CSR = tmpreg | (RCC_Time << 10);
        break;
    case RCC_StabilizationSource_HSI:
        tmpreg = RCC->CSR;
        tmpreg &= ~RCC_CSR_STARTUPHSI;
        RCC->CSR = tmpreg | (RCC_Time << 6);
        break;
    case RCC_StabilizationSource_LSE:
        tmpreg = RCC->LCSR;
        tmpreg &= ~RCC_LCSR_STARTUPLSE;
        RCC->LCSR = tmpreg | (RCC_Time << 10);
        break;
    case RCC_StabilizationSource_LSI:
        tmpreg = RCC->LCSR;
        tmpreg &= ~RCC_LCSR_STARTUPLSI;
        RCC->LCSR = tmpreg | (RCC_Time << 2);
        break;
    default:
        break;
    }
}

/**
 * @brief  Enables or disables the Internal High Speed oscillator (HSI).
 * @note   After enabling the HSI, the application software should wait on
 *         HSIRDY flag to be set indicating that HSI clock is stable and can
 *         be used to clock the PLL and/or system clock.
 * @note   HSI can not be stopped if it is used directly or through the PLL
 *         as system clock. In this case, you have to select another source
 *         of the system clock then stop the HSI.
 * @note   The HSI is stopped by hardware when entering STOP and STANDBY modes.
 * @param  NewState: new state of the HSI.
 *          This parameter can be: ENABLE or DISABLE.
 * @note   When the HSI is stopped, HSIRDY flag goes low after 6 HSI oscillator
 *         clock cycles.
 * @retval None
 */
void RCC_HSICmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        RCC->CSR |= RCC_CSR_HSION;
    }
    else
    {
        RCC->CSR &= ~RCC_CSR_HSION;
    }
}

/**
 * @brief  Configures the External Low Speed oscillator (LSE).
 * @note   As the LSE is in the Backup domain and write access is denied to this
 *         domain after reset, you have to enable write access using
 *         PWR_BackupAccessCmd(ENABLE) function before to configure the LSE
 *         (to be done once after reset).
 * @note   After enabling the LSE (RCC_LSE_ON or RCC_LSE_Bypass), the application
 *         software should wait on LSERDY flag to be set indicating that LSE clock
 *         is stable and can be used to clock the RTC.
 * @param  RCC_LSE: specifies the new state of the LSE.
 *          This parameter can be one of the following values:
 *            @arg RCC_LSE_OFF: turn OFF the LSE oscillator, LSERDY flag goes low after
 *                              6 LSE oscillator clock cycles.
 *            @arg RCC_LSE_ON: turn ON the LSE oscillator
 * @retval None
 */
void RCC_LSEConfig(uint32_t RCC_LSE)
{
    /* Check the parameters */
    assert_param(IS_RCC_LSE(RCC_LSE));

    /* Reset LSEON bits before configuring the LSE ------------------*/
    if (RCC_LSE == RCC_LSE_OFF)
    {
        /* Reset LSEON bit */
        RCC->LCSR &= ~(RCC_LCSR_LSEON);
    }
    else
    {
        /* Configure LSE */
        RCC->LCSR |= RCC_LSE;
    }
}

/**
 * @brief  Enables or disables the Internal Low Speed oscillator (LSI).
 * @note   After enabling the LSI, the application software should wait on
 *         LSIRDY flag to be set indicating that LSI clock is stable and can
 *         be used to clock the IWDG and/or the RTC.
 * @note   LSI can not be disabled if the IWDG is running.
 * @param  NewState: new state of the LSI.
 *          This parameter can be: ENABLE or DISABLE.
 * @note   When the LSI is stopped, LSIRDY flag goes low after 6 LSI oscillator
 *         clock cycles.
 * @retval None
 */
void RCC_LSICmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        RCC->LCSR |= RCC_LCSR_LSION;
    }
    else
    {
        RCC->LCSR &= ~RCC_LCSR_LSION;
    }
}

/**
 * @brief  Enables or disables the Clock Security System.
 * @note   If a failure is detected on the HSE oscillator clock, this oscillator
 *         is automatically disabled and an interrupt is generated to inform the
 *         software about the failure (Clock Security System Interrupt, CSSI),
 *         allowing the MCU to perform rescue operations. The CSSI is linked to
 *         the Cortex-M0 NMI (Non-Maskable Interrupt) exception vector.
 * @param  RCC_Source: new state of the Clock Security System.
 *          This parameter can be: RCC_HSE_CSS or RCC_LSE_CSS.
 * @param  NewState: new state of the Clock Security System.
 *          This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void RCC_ClockSecuritySystemCmd(uint32_t RCC_Source, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_RCC_CSSON(RCC_Source));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (RCC_Source == RCC_HSE_CSS)
    {
        if (NewState != DISABLE)
        {
            RCC->CSR |= RCC_CSR_CSSON;
        }
        else
        {
            RCC->CSR &= ~RCC_CSR_CSSON;
        }
    }
    else
    {
        if (NewState != DISABLE)
        {
            RCC->LCSR |= RCC_LCSR_CSSLSEON;
        }
        else
        {
            RCC->LCSR &= ~RCC_LCSR_CSSLSEON;
        }
    }
}

/**
 * @brief  Set the Clock Security System detect time.
 * @param  HSI_ClkNum: new state of the Clock Security System detect time.
 *          This parameter can be: 0x01~0xFF.
 * @retval None
 */
void RCC_ClockSecuritySystemDetectTimSet(uint8_t HSI_ClkNum)
{
    uint32_t reg;

    /* Check the parameters */
    assert_param(IS_RCC_HSE_DETECTTIME(HSI_ClkNum));

    reg = RCC->ICSCR;
    reg &= ~RCC_ICSCR_HSECCSNUM;

    RCC->ICSCR = reg | (HSI_ClkNum << 24);
}

/**
 * @brief  Selects the clock source to output on MCO pin (PA8) and the corresponding
 *         prescsaler.
 * @note   PA8 should be configured in alternate function mode.
 * @param  RCC_MCOSource: specifies the clock source to output.
 *          This parameter can be one of the following values:
 *            @arg RCC_MCOSource_NoClock: No clock selected.
 *            @arg RCC_MCOSource_LSI: LSI oscillator clock selected.
 *            @arg RCC_MCOSource_LSE: LSE oscillator clock selected.
 *            @arg RCC_MCOSource_SYSCLK: System clock selected.
 *            @arg RCC_MCOSource_HSI: HSI oscillator clock selected.
 *            @arg RCC_MCOSource_HSE: HSE oscillator clock selected.
 * @param  RCC_MCOPrescaler: specifies the prescaler on MCO pin.
 *          This parameter can be one of the following values:
 *            @arg RCC_MCOPrescaler_1: MCO clock is divided by 1.
 *            @arg RCC_MCOPrescaler_2: MCO clock is divided by 2.
 *            @arg RCC_MCOPrescaler_4: MCO clock is divided by 4.
 *            @arg RCC_MCOPrescaler_8: MCO clock is divided by 8.
 * @retval None
 */
void RCC_MCOConfig(uint32_t RCC_MCOSource, uint32_t RCC_MCOPrescaler)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_MCO_SOURCE(RCC_MCOSource));
    assert_param(IS_RCC_MCO_PRESCALER(RCC_MCOPrescaler));

    /* Get CFGR value */
    tmpreg = RCC->CFGR;
    /* Clear MCOEN bits */
    tmpreg &= ~RCC_CFGR_MCOSEN;
    RCC->CFGR = tmpreg;
    /* Clear MCOPRE[1:0] bits */
    tmpreg &= ~(RCC_CFGR_MCOPRE | RCC_CFGR_MCOSEL);
    /* Set the RCC_MCOSource and RCC_MCOPrescaler */
    tmpreg |= (RCC_MCOPrescaler | RCC_MCOSource);
    /* Store the new value */
    RCC->CFGR = tmpreg | RCC_CFGR_MCOSEN;
}

/**
 * @}
 */

/**
 * @brief  Configures the system clock (SYSCLK).
 * @note   The HSI is used (enabled by hardware) as system clock source after
 *         startup from Reset, wake-up from STOP and STANDBY mode, or in case
 *         of failure of the HSE used directly or indirectly as system clock
 *         (if the Clock Security System CSS is enabled).
 * @note   A switch from one clock source to another occurs only if the target
 *         clock source is ready (clock stable after startup delay or PLL locked).
 *         If a clock source which is not yet ready is selected, the switch will
 *         occur when the clock source will be ready.
 *         You can use RCC_GetSYSCLKSource() function to know which clock is
 *         currently used as system clock source.
 * @param  RCC_SYSCLKSource: specifies the clock source used as system clock source
 *          This parameter can be one of the following values:
 *            @arg RCC_SYSCLKSource_HSI:    HSI selected as system clock source
 *            @arg RCC_SYSCLKSource_HSE:    HSE selected as system clock source
 *            @arg RCC_SYSCLKSource_LSE:    LSE selected as system clock source
 *            @arg RCC_SYSCLKSource_LSI:    LSI selected as system clock source
 * @retval None
 */
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_SYSCLK_SOURCE(RCC_SYSCLKSource));

    tmpreg = RCC->CFGR;

    /* Clear SW[1:0] bits */
    tmpreg &= ~RCC_CFGR_SW;

    /* Set SW[1:0] bits according to RCC_SYSCLKSource value */
    tmpreg |= RCC_SYSCLKSource;

    /* Store the new value */
    RCC->CFGR = tmpreg;
}

/**
 * @brief  Returns the clock source used as system clock.
 * @param  None
 * @retval The clock source used as system clock. The returned value can be one
 *         of the following values:
 *           - 0x00: HSI used as system clock
 *           - 0x01: HSE used as system clock
 *           - 0x02: LSI used as system clock
 *           - 0x03: LSE used as system clock
 */
uint8_t RCC_GetSYSCLKSource(void)
{
    return ((uint8_t)(RCC->CFGR & RCC_CFGR_SW));
}

/**
 * @brief  Configures the AHB clock (HCLK).
 * @param  RCC_SYSCLK: defines the AHB clock divider. This clock is derived from
 *         the system clock (SYSCLK).
 *          This parameter can be one of the following values:
 *            @arg RCC_SYSCLK_Div1:   AHB clock = SYSCLK
 *            @arg RCC_SYSCLK_Div2:   AHB clock = SYSCLK/2
 *            @arg RCC_SYSCLK_Div4:   AHB clock = SYSCLK/4
 *            @arg RCC_SYSCLK_Div8:   AHB clock = SYSCLK/8
 *            @arg RCC_SYSCLK_Div16:  AHB clock = SYSCLK/16
 *            @arg RCC_SYSCLK_Div64:  AHB clock = SYSCLK/64
 *            @arg RCC_SYSCLK_Div128: AHB clock = SYSCLK/128
 * @retval None
 */
void RCC_HCLKConfig(uint32_t RCC_SYSCLK)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_HCLK(RCC_SYSCLK));

    tmpreg = RCC->CFGR;

    /* Clear HPRE[2:0] bits */
    tmpreg &= ~RCC_CFGR_HPRE;

    /* Set HPRE[2:0] bits according to RCC_SYSCLK value */
    tmpreg |= RCC_SYSCLK;

    /* Store the new value */
    RCC->CFGR = tmpreg;
}

/**
 * @brief  Configures the APB1 clock (P1CLK).
 * @param  RCC_HCLK: defines the APB1 clock divider. This clock is derived from
 *         the AHB clock (HCLK).
 *          This parameter can be one of the following values:
 *            @arg RCC_HCLK_Div1: APB1 clock = HCLK
 *            @arg RCC_HCLK_Div2: APB1 clock = HCLK/2
 *            @arg RCC_HCLK_Div4: APB1 clock = HCLK/4
 *            @arg RCC_HCLK_Div8: APB1 clock = HCLK/8
 * @retval None
 */
void RCC_PCLKConfig(uint32_t RCC_HCLK)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_PCLK(RCC_HCLK));

    tmpreg = RCC->CFGR;

    /* Clear PPRE[1:0] bits */
    tmpreg &= ~RCC_CFGR_PPRE;

    /* Set PPRE[1:0] bits according to RCC_HCLK value */
    tmpreg |= (RCC_HCLK << 2);

    /* Store the new value */
    RCC->CFGR = tmpreg;
}

/**
 * @brief  Configures the ADC clock (ADCCLK).
 * @param  RCC_ADCCLK: defines the ADC clock source. This clock is derived
 *         from the APB clock (PCLK).
 *          This parameter can be one of the following values:
 *             @arg RCC_ADCCLK_Div1: ADC clock = CLK/1
 *             @arg RCC_ADCCLK_Div2: ADC clock = CLK/2
 *             @arg RCC_ADCCLK_Div4: ADC clock = CLK/4
 *             @arg RCC_ADCCLK_Div8: ADC clock = CLK/8
 * @retval None
 */
void RCC_ADCCLKConfig(uint32_t RCC_ADCCLK)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_ADCCLK(RCC_ADCCLK));

    /* First Clear ADCSEL bit, Close ADC Clock */
    RCC->PERIENR &= ~RCC_APBENR_ADCEN;

    tmpreg = RCC->CFGR;

    /* Clear ADCPRE bit */
    tmpreg &= ~RCC_CFGR_ADCPRE;

    /* Set ADCPRE bits according to RCC_CLK value */
    tmpreg |= RCC_ADCCLK;

    /* Store the new value */
    RCC->CFGR = tmpreg;

    /* Store the new value */
    RCC->PERIENR |= RCC_APBENR_ADCEN;
}

/**
 * @brief  Configures the LPTIM clock (LPTIMCLK).
 * @param  RCC_LPTIMSource: defines the LPTIM clock source. This clock is derived
 *         from the HSI or System clock.
 *          This parameter can be one of the following values:
 *             @arg RCC_LPTIMCLK_PCLK: LPTIM clock = APB Clock (PCLK)
 *             @arg RCC_LPTIMCLK_LSI: LPTIM clock = LSI Clock
 *             @arg RCC_LPTIMCLK_LSE: LPTIM0 clock = LSE Clock
 * @retval None
 */
void RCC_LPTIMCLKConfig(uint32_t RCC_LPTIMSource)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_LPTIMCLK_SOURCE(RCC_LPTIMSource));

    tmpreg = RCC->CFGR;

    /* Clear LPTIMSEL bit */
    tmpreg &= ~RCC_CFGR_LPTIMSEL;

    tmpreg |= RCC_LPTIMSource;

    /* Store the new value */
    RCC->CFGR = tmpreg;
}

/**
 * @brief  Configures the LPUART clock (LPUARTCLK).
 * @param  RCC_LPUARTCLK: defines the LPUART clock source. This clock is derived
 *         from the HSI or System clock.
 *          This parameter can be one of the following values:
 *             @arg RCC_LPUARTCLK_PCLK: LPUART clock = APB Clock (PCLK)
 *             @arg RCC_LPUARTCLK_LSI: LPUART clock = LSI Clock
 *             @arg RCC_LPUARTCLK_LSE: LPUART clock = LSE Clock
 * @retval None
 */
void RCC_LPUARTCLKConfig(uint32_t RCC_LPUARTSource)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_LPUARTCLK_SOURCE(RCC_LPUARTSource));

    tmpreg = RCC->CFGR;

    /* Clear RNGSEL bit */
    tmpreg &= ~RCC_CFGR_LPUARTSEL;

    tmpreg |= RCC_LPUARTSource;

    /* Store the new value */
    RCC->CFGR = tmpreg;
}

/**
 * @brief  Returns the frequencies of the System, AHB and APB busses clocks.
 * @note    The frequency returned by this function is not the real frequency
 *           in the chip. It is calculated based on the predefined constant and
 *           the source selected by RCC_SYSCLKConfig():
 *
 * @param  RCC_Clocks: pointer to a RCC_ClocksTypeDef structure which will hold
 *         the clocks frequencies.
 *
 * @note   This function can be used by the user application to compute the
 *         baudrate for the communication peripherals or configure other parameters.
 * @note   Each time SYSCLK, HCLK and/or PCLK clock changes, this function
 *         must be called to update the structure's field. Otherwise, any
 *         configuration based on this function will be incorrect.
 *
 * @retval None
 */
void RCC_GetClocksFreq(RCC_ClocksTypeDef *RCC_Clocks)
{
    uint32_t u32HSI_Value;
    uint32_t tmp = 0;
    uint8_t presc = 0;

    /* Get SYSCLK source -------------------------------------------------------*/
    tmp = RCC->CFGR & RCC_CFGR_SW;

    if (RCC->CSR & RCC_CSR_HSIRANGE_24)
    {
        u32HSI_Value = HSI_VALUE_H;
    }
    else
    {
        u32HSI_Value = HSI_VALUE_L;
    }

    switch (tmp)
    {
    case 0x00: /* HSI used as system clock */
        RCC_Clocks->SYSCLK_Frequency = u32HSI_Value;
        break;
    case 0x01: /* HSE used as system clock */
        RCC_Clocks->SYSCLK_Frequency = HSE_VALUE;
        break;
    case 0x02: /* LSI used as system clock */
        RCC_Clocks->SYSCLK_Frequency = LSI_VALUE;
        break;
    case 0x03: /* LSE used as system clock */
        RCC_Clocks->SYSCLK_Frequency = LSE_VALUE;
        break;
    default: /* HSI used as system clock */
        break;
    }
    /* Compute HCLK, PCLK clocks frequencies -----------------------------------*/
    /* Get HCLK prescaler */
    tmp = RCC->CFGR & RCC_CFGR_HPRE;
    tmp = tmp >> 4;
    presc = tmp;
    /* HCLK clock frequency */
    RCC_Clocks->HCLK_Frequency = RCC_Clocks->SYSCLK_Frequency >> presc;

    /* Get PCLK1 prescaler */
    tmp = RCC->CFGR & RCC_CFGR_PPRE;
    tmp = tmp >> 2;
    presc = tmp;
    /* PCLK clock frequency */
    RCC_Clocks->PCLK_Frequency = RCC_Clocks->HCLK_Frequency >> presc;

    /* ADCCLK clock frequency */
    presc = (RCC->CFGR & RCC_CFGR_ADCPRE) >> 14;
    /* ADC Clock is derived from PCLK/PRE */
    RCC_Clocks->ADCCLK_Frequency = RCC_Clocks->PCLK_Frequency >> presc;

    /* LPTIMCLK clock frequency */
    if ((RCC->CFGR & RCC_CFGR_LPTIMSEL) == RCC_CFGR_LPTIMSEL_PCLK)
    {
        /* LPTIM Clock is from PCLK. */
        RCC_Clocks->LPTIMCLK_Frequency = RCC_Clocks->PCLK_Frequency;
    }
    else if ((RCC->CFGR & RCC_CFGR_LPTIMSEL) == RCC_CFGR_LPTIMSEL_LSI)
    {
        /* LPTIM Clock is from LSI */
        RCC_Clocks->LPTIMCLK_Frequency = LSI_VALUE;
    }
    else
    {
        /* LPTIM Clock is from LSE */
        RCC_Clocks->LPTIMCLK_Frequency = LSE_VALUE;
    }

    /* LPUARTCLK clock frequency */
    if ((RCC->CFGR & RCC_CFGR_LPUARTSEL) == RCC_CFGR_LPUARTSEL_PCLK)
    {
        /* LPUART Clock is from PCLK. */
        RCC_Clocks->LPUARTCLK_Frequency = RCC_Clocks->PCLK_Frequency;
    }
    else if ((RCC->CFGR & RCC_CFGR_LPUARTSEL) == RCC_CFGR_LPUARTSEL_LSI)
    {
        /* LPUART Clock is from LSI */
        RCC_Clocks->LPUARTCLK_Frequency = LSI_VALUE;
    }
    else
    {
        /* LPUART Clock is from LSE */
        RCC_Clocks->LPUARTCLK_Frequency = LSE_VALUE;
    }
}

/**
 * @}
 */

/**
 * @brief  Configures the RTC clock (RTCCLK).
 * @note   As the RTC clock configuration bits are in the Backup domain and write
 *         access is denied to this domain after reset, you have to enable write
 *         access using PWR_BackupAccessCmd(ENABLE) function before to configure
 *         the RTC clock source (to be done once after reset).
 * @note   Once the RTC clock is configured it can't be changed unless the RTC
 *         is reset using RCC_RTCResetCmd function, or by a Power On Reset (POR)
 *
 * @param  RCC_RTCCLKSource: specifies the RTC clock source.
 *          This parameter can be one of the following values:
 *            @arg RCC_RTCCLKSource_LSE: LSE selected as RTC clock
 *            @arg RCC_RTCCLKSource_LSI: LSI selected as RTC clock
 *            @arg RCC_RTCCLKSource_HSE_Divx: HSE divided by DIV selected as RTC clock
 *
 * @note   If the LSE or LSI is used as RTC clock source, the RTC continues to
 *         work in STOP and STANDBY modes, and can be used as wakeup source.
 *         However, when the HSE clock is used as RTC clock source, the RTC
 *         cannot be used in STOP and STANDBY modes.
 *
 *
 * @retval None
 */
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource)
{
    uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_RCC_RTCCLK_SOURCE(RCC_RTCCLKSource));

    tmpreg = RCC->LCSR;

    if ((RCC_RTCCLKSource & 0x01) == 0x01)
    {
        /* If HSE is selected as RTC clock source, configure HSE division factor for RTC clock */

        /* Clear RTCPRE[3:0] bits */
        tmpreg &= ~RCC_LCSR_RTCPRE;

        /* Configure HSE division factor for RTC clock */
        tmpreg |= (RCC_RTCCLKSource & 0xFFFFFFFE);

        /* Store the new value */
        RCC_RTCCLKSource = tmpreg;
    }

    /* Select the RTC clock source */
    RCC->LCSR = (tmpreg & (~RCC_LCSR_RTCSEL_HSE_DIV)) | RCC_RTCCLKSource;
}

/**
 * @brief  Enables or disables the RTC clock.
 * @note   This function must be used only after the RTC clock source was selected
 *         using the RCC_RTCCLKConfig function.
 * @param  NewState: new state of the RTC clock.
 *          This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void RCC_RTCCLKCmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        RCC->LCSR |= RCC_LCSR_RTCEN;
    }
    else
    {
        RCC->LCSR &= ~RCC_LCSR_RTCEN;
    }
}

/**
 * @brief  Forces or releases the RTC reset.
 * @note   This function resets the RTC peripheral.
 * @param  NewState: new state of the Backup domain reset.
 *          This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void RCC_RTCResetCmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        RCC->LCSR |= RCC_LCSR_RTCRST;
    }
    else
    {
        RCC->LCSR &= ~RCC_LCSR_RTCRST;
    }
}

/**
 * @brief  Enables or disables the AHB peripheral clock.
 * @note   After reset, the peripheral clock (used for registers read/write access)
 *         is disabled and the application software has to enable this clock before
 *         using it.
 * @param  RCC_AHBPeriph: specifies the AHB peripheral to gates its clock.
 *          This parameter can be any combination of the following values:
 *             @arg RCC_AHBPeriph_GPIOA: GPIOA clock
 *             @arg RCC_AHBPeriph_GPIOB: GPIOB clock
 *             @arg RCC_AHBPeriph_GPIOC: GPIOC clock
 *             @arg RCC_AHBPeriph_GPIOD: GPIOD clock
 *             @arg RCC_AHBPeriph_CRC:   CRC clock
 *             @arg RCC_AHBPeriph_DMA:   DMA clock
 *             @arg RCC_AHBENR_STCKEN : systick use external reference clock
 *             @arg RCC_AHBPeriph_FLASH: FLASH clock
 * @param  NewState: new state of the specified peripheral clock.
 *          This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_RCC_AHB_PERIPH(RCC_AHBPeriph));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        RCC->PERIENR |= RCC_AHBPeriph;
    }
    else
    {
        RCC->PERIENR &= ~RCC_AHBPeriph;
    }
}

/**
 * @brief  Enables or disables the High Speed APB  peripheral clock.
 * @note   After reset, the peripheral clock (used for registers read/write access)
 *         is disabled and the application software has to enable this clock before
 *         using it.
 * @param  RCC_APBPeriph: specifies the APB peripheral to gates its clock.
 *          This parameter can be any combination of the following values:
 *             @arg RCC_APBPeriph_USART0
 *             @arg RCC_APBPeriph_USART1
 *             @arg RCC_APBPeriph_SPI0
 *             @arg RCC_APBPeriph_I2C0
 *             @arg RCC_APBPeriph_TIM1
 *             @arg RCC_APBPeriph_PCA
 *             @arg RCC_APBPeriph_TIM4
 *             @arg RCC_APBPeriph_TIM5
 *             @arg RCC_APBPeriph_SYSCFG
 *             @arg RCC_APBPeriph_WWDG
 *             @arg RCC_APBPeriph_IWDG
 *             @arg RCC_APBPeriph_RTC
 *             @arg RCC_APBPeriph_ADC
 *             @arg RCC_APBPeriph_TIM2
 *             @arg RCC_APBPeriph_PWR
 *             @arg RCC_APBPeriph_LPTIM0
 *             @arg RCC_APBPeriph_LPUART0
 * @param  NewState: new state of the specified peripheral clock.
 *          This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void RCC_APBPeriphClockCmd(uint32_t RCC_APBPeriph, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_RCC_APB_PERIPH(RCC_APBPeriph));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        RCC->PERIENR |= RCC_APBPeriph;
    }
    else
    {
        RCC->PERIENR &= ~RCC_APBPeriph;
    }
}

/**
 * @brief  Forces or releases AHB peripheral reset.
 * @param  RCC_AHBPeriph: specifies the AHB peripheral to reset.
 *          This parameter can be any combination of the following values:
 *             @arg RCC_AHBPeriph_GPIOA: GPIOA reset
 *             @arg RCC_AHBPeriph_GPIOB: GPIOB reset
 *             @arg RCC_AHBPeriph_GPIOC: GPIOC reset
 *             @arg RCC_AHBPeriph_GPIOD: GPIOD reset
 *             @arg RCC_AHBPeriph_CRC:   CRC reset
 *             @arg RCC_AHBPeriph_DMA:   DMA reset
 *             @arg RCC_AHBPeriph_FLASH: FLASH reset
 * @param  NewState: new state of the specified peripheral reset.
 *          This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void RCC_AHBPeriphResetCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_RCC_AHB_RST_PERIPH(RCC_AHBPeriph));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        RCC->PERIRSTR |= RCC_AHBPeriph;
    }
    else
    {
        RCC->PERIRSTR &= ~RCC_AHBPeriph;
    }
}

/**
 * @brief  Forces or releases High Speed APB (APB2) peripheral reset.
 * @param  RCC_APB2Periph: specifies the APB2 peripheral to reset.
 *          This parameter can be any combination of the following values:
 *             @arg RCC_APBPeriph_USART0
 *             @arg RCC_APBPeriph_USART1
 *             @arg RCC_APBPeriph_SPI0
 *             @arg RCC_APBPeriph_I2C0
 *             @arg RCC_APBPeriph_TIM1
 *             @arg RCC_APBPeriph_PCA
 *             @arg RCC_APBPeriph_TIM4
 *             @arg RCC_APBPeriph_TIM5
 *             @arg RCC_APBPeriph_SYSCFG
 *             @arg RCC_APBPeriph_WWDG
 *             @arg RCC_APBPeriph_ADC
 *             @arg RCC_APBPeriph_TIM2
 *             @arg RCC_APBPeriph_PWR
 *             @arg RCC_APBPeriph_LPTIM0
 *             @arg RCC_APBPeriph_LPUART0
 * @param  NewState: new state of the specified peripheral reset.
 *          This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void RCC_APBPeriphResetCmd(uint32_t RCC_APBPeriph, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_RCC_APB_RST_PERIPH(RCC_APBPeriph));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        RCC->PERIRSTR |= RCC_APBPeriph;
    }
    else
    {
        RCC->PERIRSTR &= ~RCC_APBPeriph;
    }
}

/**
 * @}
 */

/**
 * @brief  Enables or disables the specified RCC interrupts.
 * @note   The CSS interrupt doesn't have an enable bit; once the CSS is enabled
 *         and if the HSE clock fails, the CSS interrupt occurs and an NMI is
 *         automatically generated. The NMI will be executed indefinitely, and
 *         since NMI has higher priority than any other IRQ (and main program)
 *         the application will be stacked in the NMI ISR unless the CSS interrupt
 *         pending bit is cleared.
 * @param  RCC_IT: specifies the RCC interrupt sources to be enabled or disabled.
 *          This parameter can be any combination of the following values:
 *              @arg RCC_IT_CSSHSE: CSSHSE interrupt
 *              @arg RCC_IT_CSSLSE: CSSLSE interrupt
 * @param  NewState: new state of the specified RCC interrupts.
 *          This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void RCC_ITConfig(uint8_t RCC_IT, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_RCC_IT(RCC_IT));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        /* Perform Byte access to RCC_CIR[13:8] bits to enable the selected interrupts */
        if (RCC_IT & RCC_IT_CSSHSE)
        {
            RCC->CSR |= RCC_CSR_CSSHSEIE;
        }

        if (RCC_IT & RCC_IT_CSSLSE)
        {
            RCC->LCSR |= RCC_LCSR_CSSLSEIE;
        }
    }
    else
    {
        /* Perform Byte access to RCC_CIR[13:8] bits to disable the selected interrupts */
        if (RCC_IT & RCC_IT_CSSHSE)
        {
            RCC->CSR &= ~RCC_CSR_CSSHSEIE;
        }

        if (RCC_IT & RCC_IT_CSSLSE)
        {
            RCC->LCSR &= ~RCC_LCSR_CSSLSEIE;
        }
    }
}

/**
 * @brief  Checks whether the specified RCC flag is set or not.
 * @param  RCC_FLAG: specifies the flag to check.
 *          This parameter can be one of the following values:
 *             @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready
 *             @arg RCC_FLAG_HSERDY: HSE oscillator clock ready
 *             @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready
 *             @arg RCC_FLAG_PINRSTF: Pin reset
 *             @arg RCC_FLAG_PORRSTF: POR/PDR reset
 *             @arg RCC_FLAG_LOCKUPRSTF: core lockup reset
 *             @arg RCC_FLAG_SFTRSTF: Software reset
 *             @arg RCC_FLAG_IWDGRSTF: Independent Watchdog reset
 *             @arg RCC_FLAG_WWDGRSTF: Window Watchdog reset
 *             @arg RCC_FLAG_LVDRSTF: Low Power reset
 * @retval The new state of RCC_FLAG (SET or RESET).
 */
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
{
    uint32_t tmp = 0;
    uint32_t statusreg = 0;
    FlagStatus bitstatus = RESET;

    /* Check the parameters */
    assert_param(IS_RCC_FLAG(RCC_FLAG));

    /* Get the RCC register index */
    tmp = RCC_FLAG >> 5;

    if (tmp == 0) /* The flag to check is in CSR register */
    {
        statusreg = RCC->CSR;
    }
    else if (tmp == 1) /* The flag to check is in LCSR register */
    {
        statusreg = RCC->LCSR;
    }
    else /* The flag to check is in RSTRINFO register */
    {
        statusreg = RCC->RSTRINFO;
    }

    /* Get the flag position */
    tmp = RCC_FLAG & FLAG_MASK;

    if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)
    {
        bitstatus = SET;
    }
    else
    {
        bitstatus = RESET;
    }
    /* Return the flag status */
    return bitstatus;
}

/**
 * @brief  Clears the RCC reset flags.
 *         The reset flags are: RCC_FLAG_PINRSTF,RCC_FLAG_LVDRSTF,
 *         RCC_FLAG_PORRSTF, RCC_FLAG_SFTRSTF, RCC_FLAG_IWDGRSTF, RCC_FLAG_WWDGRSTF.
 * @param  None
 * @retval None
 */
void RCC_ClearFlag(void)
{
    /* Set RMVF bit to clear the reset flags */
    RCC->RSTRINFO |= RCC_RSTRINFO_RMVF;
}

/**
 * @brief  Checks whether the specified RCC interrupt has occurred or not.
 * @param  RCC_IT: specifies the RCC interrupt source to check.
 *          This parameter can be one of the following values:
 *             @arg RCC_IT_CSSLSE: LSE Clock Security System interrupt
 *             @arg RCC_IT_CSSHSE: HSE Clock Security System interrupt
 * @retval The new state of RCC_IT (SET or RESET).
 */
ITStatus RCC_GetITStatus(uint8_t RCC_IT)
{
    ITStatus bitstatus = RESET;

    /* Check the parameters */
    assert_param(IS_RCC_GET_IT(RCC_IT));

    if (RCC_IT == RCC_IT_CSSHSE)
    {
        /* Check the status of the specified RCC interrupt */
        if ((RCC->CSR & RCC_CSR_CSSHSEF) != (uint32_t)RESET)
        {
            bitstatus = SET;
        }
        else
        {
            bitstatus = RESET;
        }
    }
    else
    {
        /* Check the status of the specified RCC interrupt */
        if ((RCC->LCSR & RCC_LCSR_CSSLSED) != (uint32_t)RESET)
        {
            bitstatus = SET;
        }
        else
        {
            bitstatus = RESET;
        }
    }

    /* Return the RCC_IT status */
    return bitstatus;
}

/**
 * @brief  Clears the RCC's interrupt pending bits.
 * @param  RCC_IT: specifies the interrupt pending bit to clear.
 *          This parameter can be any combination of the following values:
 *             @arg RCC_IT_CSSLSE: LSE Clock Security System interrupt
 *             @arg RCC_IT_CSSHSE: HSE Clock Security System interrupt
 * @retval None
 */
void RCC_ClearITPendingBit(uint8_t RCC_IT)
{
    /* Check the parameters */
    assert_param(IS_RCC_CLEAR_IT(RCC_IT));

    /* Perform Byte access to RCC_CIR[23:16] bits to clear the selected interrupt
       pending bits */
    if (RCC_IT == RCC_IT_CSSHSE)
    {
        RCC->CSR |= RCC_CSR_CSSHSEC;
    }
    else
    {
        RCC->LCSR |= RCC_LCSR_RTCRST;
        RCC->LCSR &= ~RCC_LCSR_RTCRST;
    }
}

/**
 * @brief  Adjusts the Triming calibration value.
 * @param  source: specifies the interrupt pending bit to clear.
 *          This parameter can be any combination of the following values:
 *             @arg RCC_SELECT_HSI_4M:
 *             @arg RCC_SELECT_HSI_16M:
 *             @arg RCC_SELECT_HSI_24M:
 *             @arg RCC_SELECT_LSI_32768:
 * @retval None
 */
void RCC_SET_TrimValue(uint32_t source)
{
    uint32_t TrimValue1, TrimValue2;
    uint32_t tempreg;
    uint8_t FreFlag = 0;

    switch (source)
    {
    case RCC_SELECT_HSI_4M:
        TrimValue1 = (*(__IO uint32_t *)(0x1FFFFC14));
        break;

    case RCC_SELECT_HSI_16M:
        TrimValue1 = (*(__IO uint32_t *)(0x1FFFFC18));
        break;

    case RCC_SELECT_HSI_24M:
        TrimValue1 = (*(__IO uint32_t *)(0x1FFFFC1C));
        break;

    case RCC_SELECT_LSI_32768:
        TrimValue1 = (*(__IO uint32_t *)(0X1FFFFC10));
        break;
    }
    TrimValue2 = ((~TrimValue1) >> 16) & 0xFFFF;
    TrimValue1 = TrimValue1 & 0xFFFF;

    if (TrimValue1 == TrimValue2) // 高16位和低16位互补
    {
        switch (source)
        {
        case RCC_SELECT_HSI_4M:
            TrimValue1 = (*(__IO uint32_t *)(0x1FFFFC14));
            TrimValue1 &= 0X00003F3F;
            TrimValue2 = (TrimValue1 & 0X00003F00) >> 2;
            TrimValue1 &= 0X3F;
            tempreg = RCC->ICSCR;
            tempreg &= ~(0x00000FFF);
            tempreg |= (TrimValue2 | TrimValue1);
            RCC->ICSCR = tempreg;
            break;

        case RCC_SELECT_HSI_16M:
            TrimValue1 = (*(__IO uint32_t *)(0x1FFFFC18));
            TrimValue1 &= 0X00003F3F;
            TrimValue2 = (TrimValue1 & 0X00003F00) >> 2;
            TrimValue1 &= 0X3F;
            tempreg = RCC->ICSCR;
            tempreg &= ~(0x00000FFF);
            tempreg |= (TrimValue2 | (TrimValue1));
            RCC->ICSCR = tempreg;
            break;

        case RCC_SELECT_HSI_24M:
            TrimValue1 = (*(__IO uint32_t *)(0x1FFFFC1C));
            TrimValue1 &= 0X00003F3F;
            TrimValue2 = (TrimValue1 & 0X00003F00) >> 2;
            TrimValue1 &= 0X3F;
            tempreg = RCC->ICSCR;
            tempreg &= ~(0x00000FFF);
            tempreg |= (TrimValue2 | (TrimValue1));
            RCC->ICSCR = tempreg;
            break;

        case RCC_SELECT_LSI_32768:
            TrimValue1 = (*(__IO uint32_t *)(0X1FFFFC10));
            TrimValue1 &= 0X00000F3F;
            TrimValue2 = (TrimValue1 & 0X0000F00) >> 8;
            TrimValue1 = (TrimValue1 & 0X3F) << 4;

            tempreg = RCC->LCSCR;
            tempreg &= ~(0x000003FF);
            tempreg |= (TrimValue2 | TrimValue1);
            RCC->LCSCR = tempreg | RCC_LCSCR_IOPSEL;
            break;

        default:
            break;
        }

        if (*(volatile uint32_t *)0x1FFFFC28 == 0x05FFFA00) // 频率修改标志
        {
            FreFlag = 1;
        }
        else
        {
            FreFlag = 0;
        }

        if (source == RCC_SELECT_LSI_32768)
        {
            tempreg = RCC->LCSCR;
            tempreg &= ~(0X07 << 13);
            if (FreFlag == 1)
            {
                tempreg |= (0X03 << 13); // LSI: IOPSEL = 1,RTUNE = 0X01
            }
            else
            {
                tempreg |= (0X05 << 13); // LSI: IOPSEL = 1,RTUNE = 0X02
            }

            RCC->LCSCR = tempreg;
        }
        else
        {
            tempreg = RCC->ICSCR;
            tempreg &= ~(0X07 << 12);
            if (FreFlag == 1)
            {
                tempreg |= (0X06 << 12); // HSI: HSISEL = 6
            }
            else
            {
                if (source == RCC_SELECT_HSI_4M)
                {
                    tempreg |= (0X02 << 12); // HSI: HSISEL = 2
                }
                else
                {
                    tempreg |= (0X05 << 12); // HSI: HSISEL = 5
                }
            }
            RCC->ICSCR = tempreg;
        }
    }
}
/**
 * @}
 */

/************************ (C) COPYRIGHT CHIPAT *****END OF FILE****/
